from backend.django_res.orm.models import (SupplierModel, BuyOrderModel, TakeDeliveryModel, RecvInvoiceModel,
                                           Payment4BuyOrderModel)
from backend.biz.serializers import (SupplierSerializer, BuyOrderSerializer, DeliverySerializer, InvoiceSerializer,
                                     PaymentSerializer)


class BaseBiz:
    serializer_class = None
    model_class = None

    @classmethod
    def get_serializer_class(cls):
        assert cls.serializer_class is not None, 'serializer_class can not be None'
        return cls.serializer_class

    @classmethod
    def get_serializer(cls, *args, **kwargs):
        serializer_class = cls.get_serializer_class()
        return serializer_class(*args, **kwargs)

    @classmethod
    def get_model_class(cls):
        assert cls.model_class is not None, 'model_class can not be None'
        return cls.model_class

    @classmethod
    def get_instance(cls, pk):
        if not isinstance(pk, int) or pk <= 0:
            raise ValueError('pk must be int, and > 0')

        model = cls.get_model_class()
        try:
            return model.objects.get(pk=pk)
        except model.DoesNotExist:
            raise ValueError(f'pk<{pk}> in <{model}> not exists')

    def perform_create(self, serializer):
        serializer.save()

    def create(self, data: dict, *args, **kwargs):
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return serializer.data

    def retrieve(self, pk: int, *args, **kwargs):
        instance = self.get_instance(pk)
        serializer_class = self.get_serializer_class()
        return serializer_class(instance).data

    def perform_update(self, serializer):
        serializer.save()

    def update(self, pk: int, data, *args, **kwargs):
        instance = self.get_instance(pk)
        serializer_class = self.get_serializer_class()
        serializer = serializer_class(instance, data=data, partial=True)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return serializer.data

    def perform_destroy(self, instance):
        instance.delete()

    def destroy(self, pk: int, *args, **kwargs):
        instance = self.get_instance(pk)
        self.perform_destroy(instance)

    def list(self, *args, **kwargs):
        instances = self.get_model_class().objects.all()
        serializer_class = self.get_serializer_class()
        return serializer_class(instances, many=True).data


class SupplierBiz(BaseBiz):
    serializer_class = SupplierSerializer
    model_class = SupplierModel
    default_supplier_name = 'System default supplier'

    @classmethod
    def get_default_supplier(cls):
        name = cls.default_supplier_name
        if SupplierModel.objects.filter(name=name).exists():
            return SupplierModel.objects.filter(name=name).first()
        else:
            return SupplierModel.objects.create(name=name)

    @classmethod
    def get_instance(cls, pk):
        if 0 == pk:
            return cls.get_default_supplier()
        return super().get_instance(pk)


class BuyOrderBiz(BaseBiz):
    serializer_class = BuyOrderSerializer
    model_class = BuyOrderModel

    def create(self, data, *args, **kwargs):
        supplier_id = data.get('supplier')
        if supplier_id is not None:
            if not isinstance(supplier_id, int):
                raise ValueError(f'suppler<{supplier_id}> must be supplier id')
            supplier = SupplierBiz.get_instance(supplier_id)
            data['supplier'] = supplier.id

        return super().create(data, *args, **kwargs)


class ForeignBuyOrderBiz(BaseBiz):
    def create(self, data, *args, **kwargs):
        order_id = data.get('buy_order')
        if order_id is not None:
            if not isinstance(order_id, int):
                raise ValueError(f'buy_order<{order_id}> must be supplier id')
            buy_order = BuyOrderBiz.get_instance(order_id)
            data['buy_order'] = buy_order.id

        return super().create(data, *args, **kwargs)


class DeliveryBiz(ForeignBuyOrderBiz):
    serializer_class = DeliverySerializer
    model_class = TakeDeliveryModel


class InvoiceBiz(ForeignBuyOrderBiz):
    serializer_class = InvoiceSerializer
    model_class = RecvInvoiceModel


class PaymentBiz(ForeignBuyOrderBiz):
    serializer_class = PaymentSerializer
    model_class = Payment4BuyOrderModel
